package com.sqbang.dbcompare.biz;

import com.sqbang.dbcompare.constant.CommonConst;
import com.sqbang.dbcompare.constant.Whether;
import com.sqbang.dbcompare.constant.enums.FieldTypeEnum;
import com.sqbang.dbcompare.constant.enums.RegulationCheckTypeEnum;
import com.sqbang.dbcompare.pojo.bo.*;
import com.sqbang.dbcompare.util.Tools;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

import static com.sqbang.dbcompare.constant.CommonConst.MySql.*;

/**
 * 主要业务类
 * @author suqiongbang
 * @date 2021/11/4 22:35
 */
@Component
public class MainBiz {

    @Autowired
    DatabaseBiz databaseBiz;
    @Autowired
    CheckBiz checkBiz;

    /**
     * 获取差异报告信息
     * @return
     */
    public DifferentReportBo getDifferentReport(Integer changeKey, Integer targetKey) {
        LinkedHashMap<String, TableBo> changeDatabaseTableMap = databaseBiz.getTableStruct(changeKey);
        LinkedHashMap<String, TableBo> targetDatabaseTableMap = databaseBiz.getTableStruct(targetKey);

        DifferentReportBo differentReportBo = new DifferentReportBo();
        List<DifferentReportBo.TableInfo> changeTableList = new ArrayList<>();

        for (TableBo changeTableBo : changeDatabaseTableMap.values()) {
            TableBo targetTableBo = targetDatabaseTableMap.get(changeTableBo.getTableName());
            if (targetTableBo != null) {
                changeTableBo.setIsBothHas(1);
                targetTableBo.setIsBothHas(1);

                DifferentReportBo.TableInfo tableInfo = new DifferentReportBo.TableInfo();
                tableInfo.setTableName(changeTableBo.getTableName());
                // 判断列是否改变
                this.handleColumnChange(changeTableBo, targetTableBo, tableInfo);
                // 判断索引是否改变
                this.handleIndexChange(changeTableBo, targetTableBo, tableInfo);

                if (!changeTableBo.getComment().equals(targetTableBo.getComment())) {
                    tableInfo.setIsChangeComment(1);
                    tableInfo.setChangeComment(changeTableBo.getComment());
                    tableInfo.setTargetComment(targetTableBo.getComment());
                }
                if (!CollectionUtils.isEmpty(tableInfo.getColumnInfoList())
                        || !CollectionUtils.isEmpty(tableInfo.getExtraColumnList())
                        || !CollectionUtils.isEmpty(tableInfo.getMissColumnList())
                        || !CollectionUtils.isEmpty(tableInfo.getIndexInfoList())
                        || !CollectionUtils.isEmpty(tableInfo.getExtraIndexList())
                        || !CollectionUtils.isEmpty(tableInfo.getMissIndexList())
                        || Whether.YES.equals(tableInfo.getIsChangeComment())) {
                    changeTableList.add(tableInfo);
                }
            }
        }
        differentReportBo.setChangeTableList(changeTableList);
        // 增加的
        for (TableBo changeTableBo : changeDatabaseTableMap.values()) {
            if (changeTableBo.getIsBothHas() != null && !changeTableBo.getIsBothHas().equals(1)) {
                differentReportBo.getExtraTableList().add(changeTableBo.getTableName());
            }
        }
        // 缺少的
        for (TableBo targetTableBo : targetDatabaseTableMap.values()) {
            if (targetTableBo.getIsBothHas() != null && !targetTableBo.getIsBothHas().equals(1)) {
                differentReportBo.getMissTableList().add(targetTableBo.getTableName());
            }
        }
        // 排序
        differentReportBo.getChangeTableList().sort(Comparator.comparing(DifferentReportBo.TableInfo::getTableName));
        differentReportBo.getExtraTableList().sort(String.CASE_INSENSITIVE_ORDER);
        differentReportBo.getMissTableList().sort(String.CASE_INSENSITIVE_ORDER);
        return differentReportBo;
    }

    /**
     * 处理列变动
     */
    private void handleColumnChange(TableBo changeTableBo, TableBo targetTableBo, DifferentReportBo.TableInfo tableInfo) {
        List<DifferentReportBo.FieldInfo> columnInfoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(changeTableBo.getFieldMap()) && !CollectionUtils.isEmpty(targetTableBo.getFieldMap())) {

            Map<String, FieldBo> targetColumnMap = targetTableBo.getFieldMap();
            for (FieldBo changeColumnBo : changeTableBo.getFieldMap().values()) {
                FieldBo targetColumnBo = targetColumnMap.get(changeColumnBo.getName());
                if (targetColumnBo != null) {
                    changeColumnBo.setIsBothHas(1);
                    targetColumnBo.setIsBothHas(1);

                    DifferentReportBo.FieldInfo fieldInfo = new DifferentReportBo.FieldInfo();
                    fieldInfo.setFieldName(changeColumnBo.getName());
                    boolean isChangeColumn = false;

                    if (!changeColumnBo.getFieldTypeEnum().equals(targetColumnBo.getFieldTypeEnum())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeFieldType(Whether.YES);
                        fieldInfo.setTargetFieldType(targetColumnBo.getFieldTypeEnum().toString());
                        fieldInfo.setChangeFieldType(changeColumnBo.getFieldTypeEnum().toString());
                    }
                    if (!changeColumnBo.getLength().equals(targetColumnBo.getLength())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeLength(Whether.YES);
                        fieldInfo.setTargetLength(targetColumnBo.getLength());
                        fieldInfo.setChangeLength(changeColumnBo.getLength());
                    }
                    if (!changeColumnBo.getSecondLength().equals(targetColumnBo.getSecondLength())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeSecondLength(Whether.YES);
                        fieldInfo.setTargetSecondLength(targetColumnBo.getSecondLength());
                        fieldInfo.setChangeSecondLength(changeColumnBo.getSecondLength());
                    }
                    if (changeColumnBo.getDefaultValue() != null || targetColumnBo.getDefaultValue() != null) {
                        if ((changeColumnBo.getDefaultValue() != null && !changeColumnBo.getDefaultValue().equalsIgnoreCase(targetColumnBo.getDefaultValue()))
                                || (targetColumnBo.getDefaultValue() != null && !targetColumnBo.getDefaultValue().equalsIgnoreCase(changeColumnBo.getDefaultValue()))) {
                            isChangeColumn = true;
                            fieldInfo.setIsChangeDefaultValue(Whether.YES);
                            fieldInfo.setTargetDefaultValue(targetColumnBo.getDefaultValue());
                            fieldInfo.setChangeDefaultValue(changeColumnBo.getDefaultValue());
                        }
                    }
                    if (!changeColumnBo.getComment().equalsIgnoreCase(targetColumnBo.getComment())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeComment(Whether.YES);
                        fieldInfo.setTargetComment(targetColumnBo.getComment());
                        fieldInfo.setChangeComment(changeColumnBo.getComment());
                    }
                    if (!changeColumnBo.getIsNotNull().equals(targetColumnBo.getIsNotNull())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeNotNull(Whether.YES);
                        fieldInfo.setTargetNotNull(targetColumnBo.getIsNotNull());
                        fieldInfo.setChangeNotNull(changeColumnBo.getIsNotNull());
                    }
                    if (!changeColumnBo.getIsUnsigned().equals(targetColumnBo.getIsUnsigned())) {
                        isChangeColumn = true;
                        fieldInfo.setIsChangeUnsigned(Whether.YES);
                        fieldInfo.setTargetUnsigned(targetColumnBo.getIsUnsigned());
                        fieldInfo.setChangeUnsigned(changeColumnBo.getIsUnsigned());
                    }
                    if (isChangeColumn) {
                        columnInfoList.add(fieldInfo);
                    }
                }
            }
            // 增加的
            for (FieldBo fieldBo : changeTableBo.getFieldMap().values()) {
                if (fieldBo.getIsBothHas() != null && !fieldBo.getIsBothHas().equals(1)) {
                    tableInfo.getExtraColumnList().add(fieldBo.getName());
                }
            }
            // 缺少的
            for (FieldBo fieldBo : targetTableBo.getFieldMap().values()) {
                if (fieldBo.getIsBothHas() != null && !fieldBo.getIsBothHas().equals(1)) {
                    tableInfo.getMissColumnList().add(fieldBo.getName());
                }
            }
            tableInfo.setColumnInfoList(columnInfoList);
            // 排序
            tableInfo.getColumnInfoList().sort(Comparator.comparing(DifferentReportBo.FieldInfo::getFieldName));
            tableInfo.getExtraColumnList().sort(String.CASE_INSENSITIVE_ORDER);
            tableInfo.getMissColumnList().sort(String.CASE_INSENSITIVE_ORDER);
        }
    }

    /**
     * 处理索引变动
     */
    private void handleIndexChange(TableBo changeTableBo, TableBo targetTableBo, DifferentReportBo.TableInfo tableInfo) {
        List<DifferentReportBo.IndexInfo> indexInfoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(changeTableBo.getIndexMap()) && !CollectionUtils.isEmpty(targetTableBo.getIndexMap())) {
            Map<String, IndexBo> targetIndexMap = targetTableBo.getIndexMap();
            for (IndexBo changeIndexBo : changeTableBo.getIndexMap().values()) {
                IndexBo targetIndexBo = targetIndexMap.get(changeIndexBo.getIndexName());
                if (targetIndexBo != null) {
                    changeIndexBo.setIsBothHas(1);
                    targetIndexBo.setIsBothHas(1);

                    DifferentReportBo.IndexInfo indexInfo = new DifferentReportBo.IndexInfo();
                    indexInfo.setIndexName(changeIndexBo.getIndexName());
                    boolean isChangeIndex = false;
                    if (!changeIndexBo.getNonUnique().equals(targetIndexBo.getNonUnique())) {
                        isChangeIndex = true;
                        indexInfo.setIsChangeNonUnique(Whether.YES);
                        indexInfo.setTargetNonUnique(targetIndexBo.getNonUnique());
                        indexInfo.setChangeNonUnique(changeIndexBo.getNonUnique());
                    }
                    if (!changeIndexBo.getColumnName().equals(targetIndexBo.getColumnName())) {
                        isChangeIndex = true;
                        indexInfo.setIsChangeColumnName(Whether.YES);
                        indexInfo.setTargetColumnName(targetIndexBo.getColumnName());
                        indexInfo.setChangeColumnName(changeIndexBo.getColumnName());
                    }
                    if (!changeIndexBo.getIndexType().equals(targetIndexBo.getIndexType())) {
                        isChangeIndex = true;
                        indexInfo.setIsChangeIndexType(Whether.YES);
                        indexInfo.setTargetIndexType(targetIndexBo.getIndexType());
                        indexInfo.setChangeIndexType(changeIndexBo.getIndexType());
                    }
                    if (!changeIndexBo.getIndexComment().equals(targetIndexBo.getIndexComment())) {
                        isChangeIndex = true;
                        indexInfo.setIsChangeIndexComment(Whether.YES);
                        indexInfo.setTargetIndexComment(targetIndexBo.getIndexComment());
                        indexInfo.setChangeIndexComment(changeIndexBo.getIndexComment());
                    }
                    if (isChangeIndex) {
                        indexInfoList.add(indexInfo);
                    }
                }
            }
            // 增加的
            for (IndexBo indexBo : changeTableBo.getIndexMap().values()) {
                if (indexBo.getIsBothHas() != null && !indexBo.getIsBothHas().equals(1)) {
                    tableInfo.getExtraIndexList().add(indexBo.getIndexName());
                }
            }
            // 缺少的
            for (IndexBo indexBo : targetTableBo.getIndexMap().values()) {
                if (indexBo.getIsBothHas() != null && !indexBo.getIsBothHas().equals(1)) {
                    tableInfo.getMissIndexList().add(indexBo.getIndexName());
                }
            }
            tableInfo.setIndexInfoList(indexInfoList);
            // 排序
            tableInfo.getIndexInfoList().sort(Comparator.comparing(DifferentReportBo.IndexInfo::getIndexName));
            tableInfo.getExtraIndexList().sort(String.CASE_INSENSITIVE_ORDER);
            tableInfo.getMissIndexList().sort(String.CASE_INSENSITIVE_ORDER);
        }

    }

    /**
     * 规范检查
     * @param changeKey
     * @return
     */
    public Collection<CheckReportBo> regulationCheck(Integer changeKey, String checkIds) {
        LinkedHashMap<String, TableBo> changeDatabaseTableMap = databaseBiz.getTableStruct(changeKey);
        Map<String, List<CheckReportBo.Suggest>> resultMap = new HashMap<>();
        // 判断是否检查单词拼写，并收集数据库命名中的单词，放到map<key, 单词集>
        Map<String, Set<String>> wordMap = new HashMap<>();
        boolean isCheckSpelling = false;
        if (checkIds.contains(RegulationCheckTypeEnum.NAME_ERROR_SPELL.getCode())) {
            isCheckSpelling = true;
        }
        for (TableBo changeTableBo : changeDatabaseTableMap.values()) {
            String tableName = changeTableBo.getTableName();
            checkBiz.checkWord(tableName, tableName, checkIds, resultMap);
            if (isCheckSpelling) {
                checkBiz.collectWord(tableName, tableName.toLowerCase(Locale.ROOT), wordMap);
            }

            // 表名不要使用复数名词
            if (checkIds.contains(RegulationCheckTypeEnum.TABLE_NAME_CONTAIN_PLURALITY.getCode())) {
                if (tableName.contains(CommonConst.SYMBOL_UNDERLINE)) {
                    String[] split = tableName.split(CommonConst.SYMBOL_UNDERLINE);
                    for (String name : split) {
                        checkBiz.checkPluralizeWord(name.toLowerCase(Locale.ROOT), resultMap, tableName);
                    }
                } else {
                    checkBiz.checkPluralizeWord(tableName.toLowerCase(Locale.ROOT), resultMap, tableName);
                }
            }

            // 索引命名不规范
            if (checkIds.contains(RegulationCheckTypeEnum.INDEX_NAME_ERROR.getCode())) {
                checkBiz.checkIndexName(tableName, resultMap, changeTableBo.getIndexMap());
            }

            StringBuffer columnNameSb = new StringBuffer();
            for (FieldBo changeColumnBo : changeTableBo.getFieldMap().values()) {
                String fieldName = changeColumnBo.getName();
                String key = tableName + CommonConst.SYMBOL_NUMBER_SIGN + fieldName;
                columnNameSb.append(fieldName).append(",");
                checkBiz.checkWord(fieldName, key, checkIds, resultMap);
                if (isCheckSpelling) {
                    checkBiz.collectWord(key, fieldName.toLowerCase(Locale.ROOT), wordMap);
                }

                // 字段是is开头，但类型不是unsigned tinyint
                if (checkIds.contains(RegulationCheckTypeEnum.FIELD_IS_START_ERROR_TYPE.getCode())) {
                    if (fieldName.indexOf("is_") == 0 && !FieldTypeEnum.TINYINT.equals(changeColumnBo.getFieldTypeEnum())) {
                        checkBiz.add2Map(resultMap, key, RegulationCheckTypeEnum.FIELD_IS_START_ERROR_TYPE);
                    }
                }

                // 字段是is开头，但字段备注没有包含“是否”二字
                if (checkIds.contains(RegulationCheckTypeEnum.FIELD_IS_START_ERROR_COMMENT.getCode())) {
                    if (fieldName.indexOf("is_") == 0 && !changeColumnBo.getComment().contains("是否")) {
                        checkBiz.add2Map(resultMap, key, RegulationCheckTypeEnum.FIELD_IS_START_ERROR_COMMENT);
                    }
                }

                // 字段备注包含“是否”二字，但字段名称不是is开头
                if (checkIds.contains(RegulationCheckTypeEnum.FIELD_IS_CONTAIN_COMMENT.getCode())) {
                    if (changeColumnBo.getComment().contains("是否") && fieldName.indexOf("is_") != 0) {
                        checkBiz.add2Map(resultMap, key, RegulationCheckTypeEnum.FIELD_IS_CONTAIN_COMMENT);
                    }
                }

                // 小数类型为 decimal
                if (checkIds.contains(RegulationCheckTypeEnum.FIELD_TYPE_USE_FLOAT.getCode())) {
                    if (FieldTypeEnum.FLOAT.equals(changeColumnBo.getFieldTypeEnum()) || FieldTypeEnum.DOUBLE.equals(changeColumnBo.getFieldTypeEnum())) {
                        checkBiz.add2Map(resultMap, key, RegulationCheckTypeEnum.FIELD_TYPE_USE_FLOAT);
                    }
                }
            }
            // 表缺少必备三字段
            if (checkIds.contains(RegulationCheckTypeEnum.TABLE_MISS_FIELD.getCode())) {
                String columnNameStr = columnNameSb.toString();
                if (!(columnNameStr.contains("id") && columnNameStr.contains("create_time") && columnNameStr.contains("update_time"))) {
                    checkBiz.add2Map(resultMap, tableName, RegulationCheckTypeEnum.TABLE_MISS_FIELD);
                }
            }
        }
        // 单词拼写检查
        if (isCheckSpelling) {
            long startMs = System.currentTimeMillis();
            checkBiz.checkWordSpelling2(wordMap, resultMap);
            long endMs = System.currentTimeMillis();
            System.out.println("=======================================单词拼写建议的耗时：" + (endMs - startMs) + "毫秒");
        }

        // 按key排序  正序
        Map<String, List<CheckReportBo.Suggest>> resultSortMap = resultMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        Collection<CheckReportBo> checkReportBoList = this.change2CheckReportBoList(resultSortMap);
        return checkReportBoList;
    }

    private Collection<CheckReportBo> change2CheckReportBoList(Map<String, List<CheckReportBo.Suggest>> resultSortMap){
        Map<String, CheckReportBo> tableResultMap = new LinkedHashMap<>();
        for (Map.Entry<String, List<CheckReportBo.Suggest>> entry : resultSortMap.entrySet()) {
            String key = entry.getKey();
            String tableName = key;
            String fieldName = "";
            boolean isTable = true;
            if (key.contains(CommonConst.SYMBOL_NUMBER_SIGN)) {
                String[] split = key.split(CommonConst.SYMBOL_NUMBER_SIGN);
                tableName = split[0];
                fieldName = split[1];
                isTable = false;
            }
            CheckReportBo checkReportBo = tableResultMap.get(tableName);
            if (checkReportBo == null) {
                checkReportBo = new CheckReportBo();
                checkReportBo.setName(tableName);
                if (isTable) {
                    checkReportBo.setSuggestList(entry.getValue());
                } else {
                    List<CheckReportBo> childList = new ArrayList<>();
                    CheckReportBo child = new CheckReportBo();
                    child.setName(fieldName);
                    child.setSuggestList(entry.getValue());
                    childList.add(child);
                    checkReportBo.setChildList(childList);
                }
                tableResultMap.put(tableName, checkReportBo);
            } else {
                CheckReportBo child = new CheckReportBo();
                child.setName(fieldName);
                child.setSuggestList(entry.getValue());
                List<CheckReportBo> childList = checkReportBo.getChildList();
                if (CollectionUtils.isEmpty(childList)) {
                    childList = new ArrayList<>();
                    childList.add(child);
                    checkReportBo.setChildList(childList);
                } else {
                    childList.add(child);
                }
            }
        }
        return tableResultMap.values();
    }

    /**
     * 获取差异sql
     * @param changeKey
     * @param targetKey
     * @return
     */
    public List<String> getDifferentSql(Integer changeKey, Integer targetKey) {
        LinkedHashMap<String, TableBo> changeDatabaseTableMap = databaseBiz.getTableStruct(changeKey);
        LinkedHashMap<String, TableBo> targetDatabaseTableMap = databaseBiz.getTableStruct(targetKey);

        // 排序，此处只能对表排序，不能对字段排序，因为字段的sql里面有after关键字，需要数据库中原本的循序。
        LinkedHashMap<String, TableBo> changeDatabaseTableSortMap = changeDatabaseTableMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        List<String> result = new ArrayList<>();
        for (TableBo changeTableBo : changeDatabaseTableSortMap.values()) {
            TableBo targetTableBo = targetDatabaseTableMap.get(changeTableBo.getTableName());
            List<String> strings = diffTable(changeTableBo, targetTableBo, changeKey, targetKey);
            result.addAll(strings);
        }
        return result;
    }

    /**
     * 比对表生成sql列表
     *
     * @param left
     * @param right
     * @param leftId
     * @param rightId
     * @return
     */
    private List<String> diffTable(TableBo left, TableBo right, Integer leftId, Integer rightId) {
        List<String> fixSqlList = new ArrayList<>();

        // 1.当右表不存在时，直接返回左表的建表语句
        if (null == right) {
            fixSqlList.add(this.generateWholeTableSql(leftId, left.getTableName()) + CommonConst.SYMBOL_SEMICOLON);
            return fixSqlList;
        }

        // 2.当右表存在时，比较二者差异
        LinkedHashMap<String, FieldBo> leftFieldMap = left.getFieldMap();
        LinkedHashMap<String, FieldBo> rightFieldMap = right.getFieldMap();

        String lastFieldName = null;

        Set<Map.Entry<String, FieldBo>> entries = leftFieldMap.entrySet();
        Iterator<Map.Entry<String, FieldBo>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, FieldBo> next = iterator.next();
            FieldBo leftTableField = next.getValue();
            FieldBo rightTableField = rightFieldMap.get(next.getKey());
            // 如果两个字段完全一致，则无需比较，跳过此字段
            if (null != rightTableField && isFieldEqual(leftTableField, rightTableField)) {

            } else {
                fixSqlList.add(diffField(leftTableField, rightTableField, left.getTableName(), lastFieldName));
            }
            lastFieldName = leftTableField.getName();
        }
        return fixSqlList;
    }

    /**
     * 获取单个表的整个建表sql语句
     * @param id
     * @param tableName
     * @return
     */
    public String generateWholeTableSql(Integer id, String tableName) {
        Connection conn = Tools.getConnection(id);
        if (null == conn) {
            System.out.println("获取连接失败，连接ID -> " + id);
        }
        try {
            ResultSet rs = databaseBiz.commonQuery(conn, CommonConst.MySql.QRY_SHOW_CREATE_TABLE + tableName);
            while (rs.next()) {
                return rs.getString(2);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    /**
     * 比较两个字段是否相同
     *
     * @param l
     * @param r
     * @return
     */
    private boolean isFieldEqual(FieldBo l, FieldBo r) {
        if (ObjectUtils.allNull(r)){
            return false;
        }

        if (!l.getName().equals(r.getName())) {
            return false;
        }
        if (!l.getFieldTypeEnum().equals(r.getFieldTypeEnum())) {
            return false;
        }

        Integer lengthL = l.getLength();
        Integer lengthR = r.getLength();
        if ((lengthL == null && lengthR != null)
                || (lengthL != null && lengthR == null)
                || (lengthL != null && lengthR != null && !l.getLength().equals(r.getLength()))) {
            return false;
        }

        Integer secondLengthL = l.getSecondLength();
        Integer secondLengthR = r.getSecondLength();
        if ((secondLengthL == null && secondLengthR != null)
                || (secondLengthL != null && secondLengthR == null)
                || (secondLengthL != null && secondLengthR != null && !l.getLength().equals(r.getLength()))) {
            return false;
        }

        if (!Objects.equals(l.getDefaultValue(), r.getDefaultValue())) {
            return false;
        }

        if (!Objects.equals(l.getComment(), r.getComment())) {
            return false;
        }

        if (!Objects.equals(l.getIsUnsigned(), r.getIsUnsigned())) {
            return false;
        }

        if (!Objects.equals(l.getIsNotNull(), r.getIsNotNull())) {
            return false;
        }
        if (!Objects.equals(l.getIsAutoIncr(), r.getIsAutoIncr())) {
            return false;
        }

        return true;
    }

    /**
     * 比对字段，生成sql
     *
     * @param left
     * @param right
     * @param tableName
     * @param lastFieldName 上一个字段的名称
     * @return
     */
    private String diffField(FieldBo left, FieldBo right, String tableName, String lastFieldName) {
        String sql = "";
        // 1.如果右字段不存在，返回创建左字段的sql
        if (null == right) {
            sql += DDL_ALTER_TABLE + CommonConst.SYMBOL_BACK_QUOTE + tableName + CommonConst.SYMBOL_BACK_QUOTE + DDL_ADD
                    + CommonConst.SYMBOL_BACK_QUOTE + left.getName() + CommonConst.SYMBOL_BACK_QUOTE + DDL_BLANKET
                    + left.getFieldTypeEnum().name().toLowerCase(Locale.ROOT);
        } else {
            // 2.如果右字段存在，则根据其差异生成sql
            sql += DDL_ALTER_TABLE + CommonConst.SYMBOL_BACK_QUOTE + tableName + CommonConst.SYMBOL_BACK_QUOTE + DDL_MODIFY
                    + CommonConst.SYMBOL_BACK_QUOTE + left.getName() + CommonConst.SYMBOL_BACK_QUOTE + DDL_BLANKET
                    + left.getFieldTypeEnum().name().toLowerCase(Locale.ROOT);
        }
        // 类型长度
        if (null != left.getLength() && left.getLength() > 0) {
            sql += CommonConst.SYMBOL_BRACKETS_LEFT;
            sql += left.getLength();
            if (null != left.getSecondLength() && left.getSecondLength() > 0) {
                sql += CommonConst.SYMBOL_COMMA + left.getSecondLength();
            }
            sql += CommonConst.SYMBOL_BRACKETS_RIGHT;
        }
        // 无符号
        if (Whether.YES.equals(left.getIsUnsigned())) {
            sql += DDL_UNSIGNED;
        }

        // 非空
        if (Whether.YES.equals(left.getIsAutoIncr())) {
            sql += DDL_NOT + DDL_NULL + DDL_AUTO_INCR;
        } else if (Whether.YES.equals(left.getIsNotNull())){
            sql += DDL_NOT + DDL_NULL;
        }

        // 默认值
        if (left.getDefaultValue() != null) {
            sql += DDL_DEFAULT + CommonConst.SYMBOL_S_Q + left.getDefaultValue() + CommonConst.SYMBOL_S_Q;
        } else if (!(Whether.YES.equals(left.getIsAutoIncr()) || Whether.YES.equals(left.getIsNotNull()))) {
            sql += DDL_DEFAULT + DDL_NULL;
        }

        // 注释
        if (null != left.getComment()) {
            sql += DDL_COMMENT + CommonConst.SYMBOL_S_Q + left.getComment() + CommonConst.SYMBOL_S_Q;
        }
        if (ObjectUtils.allNotNull(lastFieldName)) {
            sql += DDL_AFTER + CommonConst.SYMBOL_BACK_QUOTE + lastFieldName + CommonConst.SYMBOL_BACK_QUOTE;
        } else {
            sql += DDL_FIRST;
        }
        return sql + CommonConst.SYMBOL_SEMICOLON;
    }
}
